home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-01-19 | 13.5 KB | 698 lines | [TEXT/MMCC] |
- //
- // CTelnetTerminal.cp
- //
- // MiniTelnet application
- // Telnet terminal session document
- // PowerPlant version
- //
- // Copyright © 1993-95, FrostByte Design / Eric Scouten
- //
-
- #include "CTelnetTerminal.h"
-
- #include <LWindow.h>
-
- #include "CTerminalPane.h"
-
-
-
- // —— constructor ——
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** constructor
- **
- ** Initialize the Telnet terminal session document.
- **
- ** theDefaultPort (unsigned short): default IP port number
- ** recBufferSize (unsigned long): size of the receive buffer we need
- ** autoReceiveSize (unsigned long): number of entries in RDS for auto-receive,
- ** 0 to disable autoreceiving
- ** autoReceiveNum (unsigned short): number of auto-receive calls to issue at once
- ** must be at least 1
- ** doUseCName (unsigned Boolean): TRUE to look up canonical names for hosts
- ** printable (Boolean): TRUE if document is printable
- **
- */
-
-
-
-
- // —— creating new sessions ——
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** NewSession
- **
- ** Create a new window for document. Pulls information from the settings record which
- ** it receives and opens a session accordingly.
- **
- ** theSettings (TelnetSettingsRec*): the settings record to use
- **
- */
-
-
-
- //***********************************************************
-
-
- /*______________________________________________________________________
- **
- ** BuildWindow
- **
- ** Build a window for a terminal connection.
- **
- */
-
-
-
-
- // —— closing windows & sessions ——
-
- // -- closing windows & sessions --
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** Close
- **
- ** Respond to user close. Ensure that the TCP stream is gracefully closed. (This method is
- ** also called if the remote host closes the session or the session is terminated.)
- **
- ** quitting (Boolean): TRUE if quitting
- **
- ** return (Boolean): FALSE if close/quit aborted by user
- **
- */
-
-
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** RemoteClose
- **
- ** Respond to notification that the remote host cancelled the session (either by normal
- ** close or terminate).
- **
- */
-
- void CTelnetTerminal::RemoteClose()
-
- {
- Boolean sessionWasEstablished = SessionEstablished();
-
- CTelnetInterp::RemoteClose();
- if ((goAwayOnClose) && (!sessionWasEstablished))
- LDocument::Close();
- }
-
-
- // —— window titling ——
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** SetWindowTitle
- **
- ** Sets title for window. Turns on or off cursor blinking depending on whether session
- ** is established.
- **
- ** newTitle (Str255): the new title for the window
- **
- */
-
- void CTelnetTerminal::SetWindowTitle(Str255 newTitle)
-
- {
- if (mWindow)
- mWindow->SetDescriptor(newTitle);
- itsTerminal->SetBlinking(SessionEstablished());
- }
-
-
- // —— command/event handling ——
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** DoCommand
- **
- ** Handle all commands document can understand.
- **
- ** theCommand (long): command number that was issued
- **
- */
-
-
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** DoKeyDown
- **
- ** Process key-down events. Parses CR, LF codes and generates the
- ** standard CR/LF sequence when CR is passed and ignores LF.
- **
- ** theChar (char): the character that was entered
- ** keyCode (byte): the Mac ADB key number for the key that was pressed
- ** macEvent (EventRecord*): the entire event record
- **
- */
-
-
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** DoPaste
- **
- ** Respond to Paste command by sending all characters from the
- ** clipboard to the remote host.
- **
- */
-
- /*
- void CTelnetTerminal::DoPaste()
-
- {
- Handle theData;
- char lineBfr[83];
- char *p, *pl, *lb;
- long rem;
- short i;
-
- // get the clipboard contents
-
- if (!(gClipboard->GetData('TEXT', &theData)))
- return;
- HLock(theData);
-
- // send it in line or 80-char chunks
-
- p = (char*) *theData;
- rem = GetHandleSize(theData);
-
- while (rem > 0) {
-
- // fetch a line (or 81 chars)
-
- i = 0;
- pl = p;
- lb = lineBfr;
- while ((rem-(i) > 0) && (*pl != charCR) && (i < 80))
- i++, *lb++ = *pl++;
- if (*pl == charCR) {
- i++, *pl++;
- *lb++ = charCR;
- *lb++ = charLF;
- }
- *lb = '\0';
-
- // send the line
-
- #if _TestTerminal
- HandleNVTLine(lineBfr);
- #else
- *this << lineBfr;
- #endif
-
- rem -= i;
- p += i;
-
- }
-
- HUnlock(theData);
- DisposHandle(theData);
- }
- */
-
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** UpdateMenus
- **
- ** Enable Telnet-specific commands.
- **
- */
-
-
-
-
- // —— Telnet command handling ——
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** ReceivedDo
- **
- ** Respond to a Telnet [IAC DO option] sequence.
- **
- ** theOption (uchar): the option code
- **
- */
-
- void CTelnetTerminal::ReceivedDo(uchar theOption)
-
- {
- char respondStr[4];
-
- // parse the option and respond to it
-
- switch (theOption) {
-
- // accept terminal type option only
-
- case optTERMINAL_TYPE:
- respondStr[0] = charIAC;
- respondStr[1] = escWILL;
- respondStr[2] = theOption;
- respondStr[3] = '\0';
- if (showDebug) {
- PrintDebugStr("{IAC WILL");
- PrintDebugCharNum(theOption, ' ', '}');
- }
- *this << respondStr;
- break;
-
- // reject the remaining options
-
- default:
- CTelnetInterp::ReceivedDo(theOption);
- }
-
- }
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** ReceivedAYT
- **
- ** Respond to a Telnet [IAC AYT] sequence.
- **
- */
-
- void CTelnetTerminal::ReceivedAYT()
-
- {
- if (showDebug)
- PrintDebugStr("{Yes}");
- *this << "[Yes]";
- }
-
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** ReceivedSE
- **
- ** Parse subnegotiation parameters. Called when [IAC SE] is received.
- **
- */
-
- void CTelnetTerminal::ReceivedSE()
-
- {
- // dispatch to an option-parsing routine
-
- if (sbBfrIndex < 1)
- return;
- switch (sbBfr[0]) {
-
- case optTERMINAL_TYPE:
- OptionTerminalType();
- break;
-
- default:
- CTelnetInterp::ReceivedSE();
- }
-
- }
-
-
- // —— Telnet option handling ——
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** OptionTerminalType
- **
- ** Interpret an [IAC SB TERMINAL-TYPE ... IAC SE] sequence. Default method always says
- ** this is an unknown terminal.
- **
- */
-
- void CTelnetTerminal::OptionTerminalType()
-
- {
- char respondStr[47];
- short i = 2;
-
- // respond only to TERMINAL-TYPE SEND queries; ignore others
-
- if (sbBfr[1] == 1) {
-
- // build a response string
-
- respondStr[0] = charIAC;
- respondStr[1] = escSB;
- respondStr[2] = optTERMINAL_TYPE;
-
- // switch to next terminal emulation
-
- itsTermMode++;
- if (itsTermMode > termMax)
- itsTermMode = 0;
- // SetTerminalMode(itsTermMode);
-
- // get name of terminal emulation
-
- GetTerminalName(itsTermMode, &respondStr[3]);
-
- // display response if debugging mode enabled
-
- if (showDebug) {
- PrintDebugStr("{IAC SB TERM-TYPE IS ");
- PrintDebugStr(&respondStr[3]);
- PrintDebugStr(" IAC SE}");
- }
-
- // add end of SB string & send it
-
- while (respondStr[++i])
- ;
- respondStr[i] = charIAC;
- respondStr[i+1] = escSE;
- respondStr[i+2] = '\0';
- *this << respondStr;
- }
-
- }
-
-
- // —— terminal emulation handling ——
- //***********************************************************
-
- /*______________________________________________________________________
- **
- ** GetTerminalName
- **
- ** Return the Internet assigned name for the terminal being used.
- **
- ** termIndex (short): the terminal emulation number
- ** termStr (char*): buffer to receive the terminal name (max 40 chars)
- **
- */
-
- void CTelnetTerminal::GetTerminalName(short termIndex, char* termStr)
-
- {
- char theTerm[41] = "UNKNOWN"; // for now, all we have is “UNKNOWN”
- ::BlockMoveData(theTerm, termStr, 41);
- }
-
- void CTelnetTerminal::AttemptClose(Boolean inRecordIt)
- {
- if (LocalClose(false))
- LDocument::AttemptClose(inRecordIt);
- }
-
-
- void CTelnetTerminal::FindCommandStatus(CommandT inCommand,
- Boolean& outEnabled, Boolean& outUsesMark,
- Char16& outMark, Str255 outName)
- {
- switch (inCommand) {
-
- // Edit menu: support pasting TEXT
- /*
- case cmdPaste:
- DoPaste();
- break;
- */
-
- // Telnet menu: send various strings to server
-
- case cmd_SendSynch:
- case cmd_SendBreak:
- case cmd_SendAO:
- case cmd_SendIP:
- case cmd_SendAYT:
- case cmd_SendGA:
- case cmd_SendEC:
- case cmd_SendEL:
- case cmd_SendIPAddr:
- case cmd_ShowDebug:
- outEnabled = SessionEstablished();
- break;
-
- // not ours, send along the chain
-
- default:
- LDocument::FindCommandStatus (inCommand, outEnabled, outUsesMark, outMark, outName);
-
- }
-
-
- // enable “Paste” command only if valid Clipboard
- /*
- #if _TestTerminal
- if (gClipboard->DataSize('TEXT'))
- gBartender->EnableCmd(cmdPaste);
- #else
- if (SessionEstablished() && (gClipboard->DataSize('TEXT')))
- gBartender->EnableCmd(cmdPaste);
- #endif
- */
-
- }
-
-
- Boolean CTelnetTerminal::HandleKeyPress(const EventRecord& inKeyEvent)
-
- {
- unsigned char theChar = inKeyEvent.message & 0xFF;
-
-
- // make sure this isn’t an errant command key
-
- if (!(inKeyEvent.modifiers & cmdKey)) {
- if (theChar != 0x0A) { // TEMPORARY: we'll do constants later…
- #if _TestTerminal
- HandleNVTChar(theChar);
- if (theChar == 0x0D)
- HandleNVTChar(0x0A);
- #else
- if (!SessionEstablished()) {
- ::SysBeep(0);
- return true;
- }
-
- if (theChar == 0x08)
- SendChar(mSettings.backspaceChar);
- else
- SendChar(theChar);
-
- if (theChar == 0x0D)
- SendChar(0x0A);
- #endif
- itsTerminal->ScrollToSelection();
- }
- }
- else
- return LCommander::HandleKeyPress(inKeyEvent);
-
- return true;
-
- }
-
-
- void CTelnetTerminal::HandleNVTChar(uchar theChar)
-
- {
- itsTerminal->DoWriteChar(theChar);
- }
-
-
- void CTelnetTerminal::HandleNVTLine(char* theLine)
- {
- itsTerminal->DoWriteStr(theLine);
- }
-
-
- void CTelnetTerminal::PrintDebugCharNum(char theChar, char leftBracket, char rightBracket)
- {
- itsTerminal->DoWriteCharNum(theChar, leftBracket, rightBracket);
- }
-
-
- void CTelnetTerminal::ReceivedEL()
- {
- itsTerminal->DoEraseLine();
- }
-
-
- void CTelnetTerminal::ReceivedEC()
- {
- itsTerminal->DoEraseChar();
- }
-
-
- void CTelnetTerminal::PrintDebugStr(char* theDebugStr)
- {
- itsTerminal->DoWriteStr(theDebugStr);
- }
-
-
- Boolean CTelnetTerminal::ObeyCommand(CommandT inCommand, void* ioParam)
-
- {
- switch (inCommand) {
-
- // Edit menu: support pasting TEXT
- /*
- case cmdPaste:
- DoPaste();
- break;
- */
-
- // Telnet menu: send various strings to server
-
- case cmd_SendSynch:
- if (showDebug)
- PrintDebugStr("{Urgent IAC DM}");
- SetNextUrgent();
- *this << "\377\362";
- break;
-
- case cmd_SendBreak:
- if (showDebug)
- PrintDebugStr("{Urgent IAC BRK IAC DM}");
- SetNextUrgent();
- *this << "\377\363\377\362";
- break;
-
- case cmd_SendAO:
- if (showDebug)
- PrintDebugStr("{Urgent IAC AO IAC DM}");
- SetNextUrgent();
- *this << "\377\365\377\362";
- break;
-
- case cmd_SendIP:
- if (showDebug)
- PrintDebugStr("{Urgent IAC IP IAC DM}");
- SetNextUrgent();
- *this << "\377\364\377\362";
- break;
-
- case cmd_SendAYT:
- if (showDebug)
- PrintDebugStr("{Urgent IAC AYT IAC DM}");
- SetNextUrgent();
- *this << "\377\366\377\362";
- break;
-
- case cmd_SendGA:
- if (showDebug)
- PrintDebugStr("{IAC GA}");
- *this << "\377\371";
- break;
-
- case cmd_SendEC:
- if (showDebug)
- PrintDebugStr("{IAC EC}");
- *this << "\377\367";
- break;
-
- case cmd_SendEL:
- if (showDebug)
- PrintDebugStr("{IAC EL}");
- *this << "\377\370";
- break;
-
- case cmd_SendIPAddr:
- *this << local_IP;
- break;
-
- case cmd_ShowDebug:
- showDebug = !showDebug;
- mSettings.showDebug = showDebug;
- break;
-
- // not ours, send along the chain
-
- default:
- return LDocument::ObeyCommand(inCommand, ioParam);
- }
-
- return true;
-
- }
-
-
- void CTelnetTerminal::NewSession(TelnetSettingsRec& inSettings)
-
- {
- // copy the settings record
-
- ::BlockMoveData(&inSettings, &mSettings, sizeof (TelnetSettingsRec));
- ::BlockMoveData(mSettings.hostName, hostCName, 256);
- goAwayOnClose = mSettings.closeOnSessionEnd;
- showDebug = mSettings.showDebug;
-
-
- // build a window immediately
-
- mWindow = LWindow::CreateWindow(PPobTelnet, this);
- ThrowIfNil_(mWindow);
- itsTerminal = (CTerminalPane*) mWindow->FindPaneByID('TERM'); //! TEMPORARY: constants later
- ThrowIfNil_(itsTerminal);
- StateChanged();
-
-
- // open host by name
-
- #if _TestTerminal
- itsTerminal->DoWriteStr("No TCP session. Just type onto terminal.\mSettings\n");
- #else
- SetOpenTimeout(20);
- OpenUserHost((char*) mSettings.hostName, defaultPort, TRUE);
- #endif
-
- }
-
-
- void CTelnetTerminal::GetFileName(Str255 theName)
- {
- GetDescriptor(theName);
- }
-
-
- CTelnetTerminal::CTelnetTerminal(LCommander* inSuper,
- unsigned short theDefaultPort,
- unsigned long recBufferSize ,
- unsigned short autoReceiveSize ,
- unsigned short autoReceiveNum ,
- Boolean doUseCName )
- : LSingleDoc(inSuper),
- CTelnetInterp(theDefaultPort, recBufferSize, autoReceiveSize, autoReceiveNum, doUseCName)
-
- {
- itsTerminal = nil;
- itsTermMode = 0;
- showFileName = false;
- }
-
-
-